
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections.Generic;
using System.Text;

using Swaf;
using Swaf.BizObj;
using Swaf.Gui;
using Swaf.Gui.AspNet2;
using Swaf.Security;

namespace Syrinx.Gui.AspNet.Nitobi2
{
	public class Combo : Nitobi.Combo, IBizObjListDisplay2, INitobiClientControl
	{
		protected static string s_ajaxUrl = "/NitobiLiveStreamHandler.aspx?pi={0}&bpi={1}";
		protected string m_parentBizProcIds = null;
		protected bool m_createOnLoad = true;
		protected Privileges m_editPriv = Privileges.ReadOnly;
		protected int m_maxElements = -1;
		protected string m_dataSourceBizRule = null;
		protected string m_dataDetailBizRule = null;
		protected object m_dataSourceBizRuleParam = null;
		protected ComboSelectAction m_selectAction = ComboSelectAction.TriggerBizProcSelect;
        protected bool m_eventNeedsRefresh = false;
        protected bool m_mySelectEvent = false;
		protected object m_selectedKeyValue = null;

		public Combo()
		{
		}

		public Combo(ActiveWidget widget)
		{
			ID = widget.State.Id;
		}
		//DrivesBizProc
		public ComboSelectAction SelectAction { get { return m_selectAction; } set { m_selectAction = value; } }

		protected virtual void processBizObjSelected(string bizObjId)
		{
			ActiveBizProc bizproc = BPC.getActiveBizProc(State.ParentBizProcIds[0]);
			bizproc.BizProc.selectBizObj(bizObjId, this);
		}

		protected override void OnLoad(EventArgs e)
		{
			base.OnLoad(e);
			if (m_createOnLoad)
			{
                bool hasOfflineStateAlready = BPC.getWidgetOfflineState(WidgetId) != null;
                WidgetOfflineState offlineState = State;
				ActiveWidget act = new ActiveWidget(this, BPC, offlineState);
                act.CreatedFromPage = !hasOfflineStateAlready;
				BPC.defineActiveWidget(act);
				if (offlineState.State.get("m_selectAction") == null)
					offlineState.State.put("m_selectAction", m_selectAction);
			}

			Page.ClientScript.RegisterClientScriptBlock(typeof(Combo), "PerCombo",
				string.Format(@""), true);

			ActiveBizProc bizproc = null;
			if(State.ParentBizProcIds != null && State.ParentBizProcIds.Count > 0)
				bizproc = BPC.getActiveBizProc(State.ParentBizProcIds[0]);

			string dataUrl = string.Format("/NitobiLiveStreamHandler.aspx?pi={0}", BPC.PageState.PageId);
			dataUrl = Page.Response.ApplyAppPathModifier(dataUrl);
			if (bizproc != null)
				dataUrl = dataUrl + "&bpi=" + bizproc.OfflineState.Id;
			if (DataSourceBizRule != null)
				dataUrl = dataUrl + "&br=" + DataSourceBizRule;

			this.GetDataUrl = dataUrl;
			this.Select += new EventHandler(Combo_Select);
		}

		protected override void OnPreRender(EventArgs e)
		{
			base.OnPreRender(e);
			ActiveBizProc bizproc = null;
			if (State.ParentBizProcIds.Count > 0)
			{
				bizproc = BPC.getActiveBizProc(State.ParentBizProcIds[0]);
				if (bizproc != null)
				{
					ClientEvents.Load = string.Format(s_innerRegisterScript, ClientID, bizproc.OfflineState.Id) + ClientEvents.Load;
					if (m_selectAction == ComboSelectAction.TriggerBizProcSelect)
						ClientEvents.Select += string.Format(s_triggerScript, ClientID, bizproc.OfflineState.Id);
					else if(m_selectAction == ComboSelectAction.RefreshOnly)
						ClientEvents.Select += string.Format(s_refreshTriggerScript, ClientID, bizproc.OfflineState.Id);
				}
			}

			//The following is done because a combo can be a field inside of a bizobj display that gets its list of
			//data from an outside bizproc.  Sometimes, by the time the combo is created, the bizproc has already told all
			//of its lists to show their bizobjs but at that this combo was not a child list yet as it had not been created.
			//By doing this check we are pushing our parent bizproc's source bizobjlist into ourselves for render.
			//This is only an issue for the Unbound mode, which will need the data right now in order to render the contents.
			//Other modes involve ajax calls and the combo doesnt really need the data now anyway.
			if (Mode == Nitobi.ComboMode.Unbound && Data.provider().getDataSource() == null && Cmn.IsEmpty(DataSourceBizRule) && !Cmn.IsEmpty(ParentBizProcIds))
				Data.provider().setDataSource(bizproc.BizProc.SourceBizObjs);
		}
		protected static string s_innerRegisterScript = @"var cctl = new ClientControl(nitobi.getComponent('{0}'), setComboState, getComboState);cctl.id = '{0}';{1}BizProc.addClientControl(cctl);";
		protected static string s_triggerScript = "var combo = nitobi.getComponent('{0}');{1}BizProc.triggerEvent('{0}', 'bizObjSelected', combo.GetSelectedRowValues()[0]);";
		protected static string s_refreshTriggerScript = "var combo = nitobi.getComponent('{0}');{1}BizProc.triggerEvent('{0}', 'bizObjRefresh', combo.GetSelectedRowValues()[0]);";

		void Combo_Select(object sender, EventArgs e)
		{
			if (State.ParentBizProcIds.Count > 0)
			{
				ActiveBizProc bizproc = BPC.getActiveBizProc(State.ParentBizProcIds[0]);
				bizproc.BizProc.selectBizObj(SelectedValues[0], this);
			}
		}

		public override Nitobi.XmlDataHandler Data
		{
			get
			{
				if (Mode == Nitobi.ComboMode.Unbound && DataSourceBizRule != null && m_dataHandler == null)
					Data = new SyxXmlDataHandler(Page, DataSourceBizRule);
				return base.Data;
			}
		}

		protected BizProcCoordinator BPC
		{
			get { return (Page is IPage) ? ((IPage)Page).BPC : null; }
		}

		protected WidgetOfflineState State
		{
			get
			{
				WidgetOfflineState state = BPC == null ? null : BPC.getWidgetOfflineState(WidgetId);
				if (state == null && BPC != null)
				{
					BPC.addWidgetOfflineState(state = new WidgetOfflineState(WidgetId, this.GetType().AssemblyQualifiedName));
					state.setParentBizProcIds(m_parentBizProcIds);
					state.BizProcWidgetType = this.BizProcWidgetType;
				}
				return state;
			}
		}

		#region IBizObjListDisplay2 Members

		public string DataDetailBizRule { get { return m_dataDetailBizRule; } set { m_dataDetailBizRule = value; } }
		public string DataSourceBizRule { get { return m_dataSourceBizRule; } set { m_dataSourceBizRule = value; } }
		public object DataSourceBizRuleParam { get { return m_dataSourceBizRuleParam; } set { m_dataSourceBizRuleParam = value; } }

		#endregion

		#region IBizObjListDisplay Members

		public event BizObjChanged BizObjAdded;

		public event BizObjChanged BizObjDeleted;

		public event BizObjSelectedInfo BizObjSelected;

		public event BizObjChanged BizObjUpdated;

		public Privileges EditPrivilege { get { return m_editPriv; } set { m_editPriv = value; } }
		public string MaxElements { get { return m_maxElements.ToString(); } set { m_maxElements = int.Parse(value); } }

		public IBizObj SelectedBizObj
		{
			get
			{
				return null;
				//throw new NotImplementedException();
			}
			set
			{
				SelectedValues.Clear();
				for(int p = 0; p < Columns.Columns.Count; p++)
				{
					Nitobi.Column c = Columns.Columns[p];
					object objVal = c.getValueForRow("", value);
					string val = objVal==null?"":objVal.ToString();
					SelectedValues.Add(val);
					if (c.Name.CompareTo(DataTextField) == 0)
						m_initialValue = val;
				}
			}
		}

		public object SelectedBizObjKeyValue
		{
			get
			{
				throw new NotImplementedException();
			}
			set
			{
				m_selectedKeyValue = value;
				IBizObj selectedDetail = null;
				IBizObjList list = Data.provider().getDataSource() as IBizObjList;
				if (list != null && value != null)
					selectedDetail = list.search(list.objectType.KeyFieldNames, value);
				if(selectedDetail == null && DataSourceBizRule != null)
				{
					IResults rc = Swaf.Application.currentApp.ruleMgr.execute(DataSourceBizRule);
					list = rc.CallResults as IBizObjList;
					if (list != null)
						selectedDetail = list.search(Columns.Columns[0].Name, value);
						//selectedDetail = list.search(list.objectType.KeyFieldNames, value);

					if(rc.ExceptionInfo != null)
					{
						//TODO:Should we show an error to user or just let it go and rely on the fact that the rule failure
						//was logged already??
					}
				}

				if (selectedDetail != null)
					SelectedBizObj = selectedDetail;
			}
		}

		public void getSelectedBizObjs(IBizObjList selected)
		{
			throw new NotImplementedException();
		}

		public void setSelectedBizObjs(IBizObjList selected)
		{
			throw new NotImplementedException();
		}

		public void showBizObjs(IBizObjCursor cur)
		{
			IBizObjList list = cur.Source;
			Data.provider().setDataSource(list);
			if (m_selectedKeyValue != null)
				SelectedBizObjKeyValue = m_selectedKeyValue;
		}

		public void updateBizObjs()
		{
		//	throw new NotImplementedException();
		}

		public virtual void refresh()
		{
            m_eventNeedsRefresh = true;
		}
		#endregion

		#region IWidget Members


		public BizProcWidgetType BizProcWidgetType { get { return BizProcWidgetType.list; } set { } }

		public string ParentBizProcIds { get { return (string)getOffline("m_parentBizProcIds"); } set { putOffline("m_parentBizProcIds", value); if(BPC != null)State.setParentBizProcIds(value); } }

		public string WidgetId
		{
			get { return ClientID; }
		}

		#endregion

		#region INitobiClientControl Members

		public void setState(System.Xml.XmlElement clientState)
		{
            ActiveBizProc bizproc = BPC.getActiveBizProc(State.ParentBizProcIds[0]);
            string ajaxEvent = clientState.OwnerDocument.DocumentElement.GetAttribute("event").ToLower();
            bool mybizProc = clientState.OwnerDocument.DocumentElement.GetAttribute("bizProcId").CompareTo(bizproc.OfflineState.Id) == 0;
            if (ajaxEvent.CompareTo("bizobjselected") == 0 && mybizProc)
                m_mySelectEvent = true;
            else// if (mybizProc)
                m_eventNeedsRefresh = true;
        }

		public void getState(System.Xml.XmlElement clientState, string pageHtml)
		{
            if (m_eventNeedsRefresh)
                clientState.SetAttribute("refresh", "true");
        }

		public void processAjaxEvent(System.Xml.XmlElement eventInfo)
		{
			if (eventInfo.GetAttribute("event").CompareTo("bizObjSelected") == 0)
			{
				string bizObjId = eventInfo.GetAttribute("value");
				processBizObjSelected(bizObjId);
			}
			else if (eventInfo.GetAttribute("event").CompareTo("bizObjRefresh") == 0)
			{
				ActiveBizProc bizproc = BPC.getActiveBizProc(State.ParentBizProcIds[0]);
				if (bizproc != null)
					bizproc.BizProc.updateBizObj(true);
			}
		}

		public bool CreateOnLoad { set { m_createOnLoad = value; } }

		public bool NeedToGenerateHtmlWithServerControls { get { return false; } }

		#endregion

		protected void putOffline(string keyName, object val)
		{
			if (BPC != null)
				State.State.put(keyName, val);
			Cmn.callPropertySet(this, keyName, val);
		}
		protected object getOffline(string keyName)
		{
			object v = BPC == null ? null : State.State.get(keyName);
			if (v == null)
				v = Cmn.callPropertyGet(this, keyName);
			return v;
		}
	}

	public enum ComboSelectAction {DoNothing, TriggerBizProcSelect, RefreshOnly};
}
